package net.cl.mvc.dispatcher;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.cl.mvc.Globals;
import net.cl.mvc.config.ActionMapping;
import net.cl.mvc.pages.GlobalError;
import net.cl.mvc.pages.MethodNotImplemented;
import net.cl.mvc.pages.PageNotFound;
import net.cl.mvc.wrappers.ActionContext;
import net.cl.mvc.wrappers.RequestContext;
import net.cl.mvc.wrappers.ResponseContext;
import net.cl.utils.StringUtil;

public class Dispatcher {

	public static String invoke(ServletRequest request, ServletResponse response) {
		String className = null;
		try {
			HttpServletRequest req = (HttpServletRequest) request;
			HttpServletResponse rep = (HttpServletResponse) response;
			ActionContext actionContext = ActionContext.getContext();
			actionContext.setRequestContext(new RequestContext(req));
			actionContext.setResponseContext(new ResponseContext(rep));
			ActionContext.setContext(actionContext);
			className = ActionMapping.getMapping(req.getServletPath());
			if (className == null) {
				// toPageNotFound();
				request.setAttribute(Globals.NEXT_CHAIN_KEY, Boolean.TRUE);
				return req.getServletPath();
			}
			Class<?> clazz = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
			Object o = clazz.newInstance();
			Method m = clazz.getDeclaredMethod(Globals.EXECUTE_METHOD_NAME);
			String s = (String) m.invoke(o);
			Method[] ms = clazz.getDeclaredMethods();
			for (int i = 0; i < ms.length; i++) {
				String name = ms[i].getName();
				if (name.startsWith("get"))
					request.setAttribute(StringUtil.firstLower(name.substring(3)), ms[i].invoke(o));
			}
			return s;
		} catch (NoSuchMethodException e) {
			request.setAttribute(Globals.MESSAGE_KEY, className);
			toMethodNotImplemented();
		} catch (Exception e) {
			request.setAttribute(Globals.EXCEPTION_KEY, e);
			toErrorPage();
		}
		return null;
	}

	public static void toErrorPage() {
		try {
			GlobalError ge = new GlobalError();
			ge.execute();
		} catch (Exception e) {
			e.printStackTrace();// TODO
		}
	}

	public static void toPageNotFound() {
		try {
			PageNotFound pnf = new PageNotFound();
			pnf.execute();
		} catch (Exception e) {
			e.printStackTrace();// TODO
		}
	}

	public static void toMethodNotImplemented() {
		try {
			MethodNotImplemented mni = new MethodNotImplemented();
			mni.execute();
		} catch (Exception e) {
			e.printStackTrace();// TODO
		}
	}

}
